/*
 *  SSCommentView.m
 *  MESLib
 * 
 * Copyright 2003-2009 Starline Software Ltd
 * 
 * This file is part of MESLib.
 * 
 * MESLib is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MESLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with MESLib. If not, see <http://www.gnu.org/licenses/>.
 */
//  Created by Tobias Haughton on Thu Feb 06 2003.
//

#import "SSCommentView.h"
#import "SSCatalystComment.h"
#import "SSChartView.h"
#import "SSCatalystDocument.h"

@implementation SSCommentView

- (id)initWithFrame:(NSRect)frame
             string:(NSString *)commentString
               type:(NSNumber *)type
              owner:(SSCatalystComment *)own {
    self = [super initWithFrame:frame];
    if (self) {
       NSNotificationCenter *nc  = [NSNotificationCenter defaultCenter];
       [nc addObserver:self
              selector:@selector(setPaths)
                  name:@"NSViewFrameDidChangeNotification"
                object:self];

       [self setOwner:own];
       [self setCommentImage];
       [self createMenu];
       [self setPaths];

       testCellBounds = NSMakeRect(0, 0, SSCommentFieldLength, 10000); //used to get a size for the text field
       
       imagePoint = NSMakePoint(2, 2);
       fromRect = NSMakeRect(0, 0, [commentImage size].width, [commentImage size].height);
       
       //setup the field
       NSFont *font = [NSFont fontWithName:@"Helvetica" size:10];
       commentField = [[[NSTextField alloc]
          initWithFrame:NSMakeRect(([commentImage size].width + 3), 7, SSCommentFieldLength, SSEventFieldHeight)] autorelease];
       [commentField setStringValue:commentString];
       [[commentField cell] setBordered:NO];
       [[commentField cell] setFont:font];
       [commentField setDrawsBackground:NO];
       [commentField setDelegate:self];
       [commentField setSelectable:NO];
       [[commentField cell] setWraps:YES];
       [self addSubview:commentField];

       [self resizeSelfAndField]; //in case the string is too long to fit in a single field
    }
    return self;
}

- (id)initWithCommentView:(SSCommentView *)view {
   self = [super initWithFrame:[view frame]];
   if (self) {
      [self setOwner:[view owner]];
      [self setCommentImage];
      [self createMenu];
      [self setPaths];

      testCellBounds = NSMakeRect(0, 0, SSCommentFieldLength, 10000); //used to get a size for the text field

      imagePoint = NSMakePoint(2, 2);
      fromRect = NSMakeRect(0, 0, [commentImage size].width, [commentImage size].height);

      //setup the field
      NSFont *font = [NSFont fontWithName:@"Helvetica" size:10];
      commentField = [[[NSTextField alloc]
          initWithFrame:NSMakeRect(([commentImage size].width + 3), 7, SSCommentFieldLength, SSEventFieldHeight)] autorelease];
      [commentField setStringValue:[owner commentString]];
      [[commentField cell] setBordered:NO];
      [[commentField cell] setFont:font];
      [commentField setDrawsBackground:NO];
      [commentField setDelegate:self];
      [commentField setSelectable:NO];
      [[commentField cell] setWraps:YES];
      [self addSubview:commentField];

      [self resizeSelfAndField]; //in case the string is too long to fit in a single field
   }
   return self;
}

- (void)drawRect:(NSRect)rect {
   [[NSColor whiteColor] set];
   [borderPath fill];
   
   [commentImage drawAtPoint:imagePoint fromRect:fromRect
                   operation:NSCompositeSourceOver
                    fraction:1.0];

   //set the color for the border based on the comment type
   switch([[owner type] intValue]) {
      case SSCommentQuestionType:[[NSColor redColor] set];
         break;
      case SSCommentNoteType:[[NSColor orangeColor] set];
         break;
      default:[[NSColor yellowColor] set];
         break;
   }
   [borderPath stroke];

   if(isSelected) {
      //show that we are selected
      NSBezierPath *selectedPath = [borderPath copy];
      [selectedPath setLineWidth:10];
      [SSSelectedColor set];
      [selectedPath stroke];
   }
}

//***********************************mouse events
- (void)mouseDown:(NSEvent *)theEvent
{
   NSPoint p = [theEvent locationInWindow];
   NSPoint converted = [[self superview] convertPoint:p fromView:nil];

   if(([theEvent modifierFlags] & NSCommandKeyMask) || ([theEvent modifierFlags] & NSShiftKeyMask)) {
      if(isSelected) { //already selected we want to remove our selected status
         [(SSChartView *)[self superview] invalidateSelectionForObject:self];
      } else { //using command key they are selecting multiple views
         [(SSChartView *)[self superview] markAsSelected:self byAddingToSelection:YES];
      }
   } else { //no command just select us
      [(SSChartView *)[self superview] markAsSelected:self byAddingToSelection:NO];
   }

   [(SSChartView *)[self superview] setSelectedViewsDistanceFromOrigin:converted];

   if([theEvent clickCount] == 2) { //if user double clicks see if it is above our text field and if so allow editing
      [self allowEditingInFieldIfUnderPoint:p];
   } else {
      if(([theEvent modifierFlags] & NSControlKeyMask)) {//user is trying to change comment type
         [self setMenu:[self menuForEvent:theEvent]];
      } else {
         [commentField setSelectable:NO];
         [commentField setEditable:NO];
         [commentField setBordered:NO];
         [[self window] makeFirstResponder:[self superview]];
      }
   }
}

- (void)mouseDragged:(NSEvent *)theEvent
{
   NSPoint p = [theEvent locationInWindow];
   NSPoint converted = [[self superview] convertPoint:p fromView:nil];

   [(SSChartView *)[self superview] setSelectedViewsOriginWithPoint:converted];
}

- (void)mouseUp:(NSEvent *)theEvent
{
   //our position has changed so our closest event could have too
   [owner setClosestEvent];
   
   if(![commentField isEditable]) {
      //make superview first responder so that we can copy and paste
      [[self window] makeFirstResponder:[self superview]];
   }
}


//***********************************
- (void)setDistanceFromOrigin:(NSPoint)point
{
   distanceFromOrigin.x = point.x - [self frame].origin.x;
   distanceFromOrigin.y = point.y - [self frame].origin.y;
}

- (void)setNewOriginWithPoint:(NSPoint)point
{
   NSPoint newOrigin;
   NSRect oldFrame = [self frame];
   NSRect displayArea;
   newOrigin.x = point.x - distanceFromOrigin.x;
   newOrigin.y = point.y - distanceFromOrigin.y;
   
   [self setFrameOrigin:newOrigin];

   if(NSMinX([self frame]) > NSMinX(oldFrame)) {
      //we are moving right
      if(NSMinY([self frame]) > NSMinY(oldFrame)) {
         //we are moving down
         displayArea = NSMakeRect((NSMinX(oldFrame) - 5), (NSMinY(oldFrame) - 5), (NSMaxX([self frame]) - NSMinX(oldFrame) + 10), (NSMaxY([self frame]) - NSMinY(oldFrame) + 10));
         [[self superview] setNeedsDisplayInRect:displayArea];
      } else {
         //we are moving up
         displayArea = NSMakeRect((NSMinX(oldFrame) - 5), (NSMinY([self frame]) - 5), (NSMaxX([self frame]) - NSMinX(oldFrame) + 10), (NSMaxY(oldFrame) - NSMinY([self frame]) + 10));
         [[self superview] setNeedsDisplayInRect:displayArea];
      }
   } else {
      //we are moving left
      if(NSMinY([self frame]) > NSMinY(oldFrame)) {
         //we are moving down
         displayArea = NSMakeRect((NSMinX([self frame]) - 5), (NSMinY(oldFrame) - 5), (NSMaxX(oldFrame) - NSMinX([self frame]) + 10), (NSMaxY([self frame]) - NSMinY(oldFrame) + 10));
         [[self superview] setNeedsDisplayInRect:displayArea];
      } else {
         //we are moving up
         displayArea = NSMakeRect((NSMinX([self frame]) - 5), (NSMinY([self frame]) - 5), (NSMaxX(oldFrame) - NSMinX([self frame]) + 10), (NSMaxY(oldFrame) - NSMinY([self frame]) + 10));
         [[self superview] setNeedsDisplayInRect:displayArea];
      }
   }

   [[[NSDocumentController sharedDocumentController] currentDocument] updateChangeCount:NSChangeDone];
}

//***********************************

- (BOOL)isSelected
{
   return isSelected;
}

- (void)setSelected
{
   isSelected = YES;
   [self setNeedsDisplay:YES];
}

- (void)setUnselected
{
   isSelected = NO;
   [self setNeedsDisplay:YES];
}

//***********************************

- (BOOL)isFullyWithinRect:(NSRect)rect
{
   NSPoint origin = [[self superview] convertPoint:[self bounds].origin fromView:self];

   if(origin.x > NSMinX(rect)) { //it's ok on the left
      if(origin.x + NSWidth([self bounds]) < NSMaxX(rect)) { //it's ok on the right
         if(origin.y > NSMinY(rect)) { //it's ok at the bottom
            if(origin.y + NSHeight([self bounds]) < NSMaxY(rect)) { //it's ok at top
                                                                    //it's fullyWithinRect
               return YES;
            }
         }
      }
   }
   return NO;
}

//***********************************menu
- (void)createMenu
{
   //build our menu
   commentMenu = [[NSMenu alloc] initWithTitle:@"menu"];
   NSMenuItem *item = [[NSMenuItem alloc] init];

   [item setTitle:NSLocalizedString(@"ChangeComment", nil)];
   [commentMenu addItem:item];
   [item release];

   item = [[NSMenuItem alloc] init];
   [item setTitle:NSLocalizedString(@"Alert", nil)];
   [item setTarget:self];
   [item setAction:@selector(setTypeFromMenu:)];
   [item setTag:SSCommentAlertType];
   [item setImage:[NSImage imageNamed: @"alertMenuImage.jpg"]];
   [commentMenu addItem:item];
   [item release];

   item = [[NSMenuItem alloc] init];
   [item setTitle:NSLocalizedString(@"Note", nil)];
   [item setTarget:self];
   [item setAction:@selector(setTypeFromMenu:)];
   [item setTag:SSCommentNoteType];
   [item setImage:[NSImage imageNamed: @"noteMenuImage.jpg"]];
   [commentMenu addItem:item];
   [item release];

   item = [[NSMenuItem alloc] init];
   [item setTitle:NSLocalizedString(@"Question", nil)];
   [item setTarget:self];
   [item setAction:@selector(setTypeFromMenu:)];
   [item setTag:SSCommentQuestionType];
   [item setImage:[NSImage imageNamed: @"questionMenuImage.jpg"]];
   [commentMenu addItem:item];
   [item release];
}

- (NSMenu *)menuForEvent:(NSEvent *)theEvent
{
   return [self menu];
}

- (NSMenu *)menu
{
   return commentMenu;
}

- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
   if([menuItem tag] == [[owner type] intValue]) {
      //this menu item is the same as the comment type so disable it
      return NO;
   } else {
      return YES;
   }
}

//***********************************
- (void)allowEditingInFieldIfUnderPoint:(NSPoint)point
{
   point = [self convertPoint:point fromView:nil];

   if(point.x > NSMinX([commentField frame]) && point.x < NSMaxX([commentField frame])) {
      //it is within the x range of this object
      if(point.y > NSMinY([commentField frame]) && point.y < NSMaxY([commentField frame])) {
         //double click was above this field make it editable
         [self selectFieldForEditing];
      }
   }
}

- (void)selectFieldForEditing
{
   //add a border and select the field
   [commentField setEditable:YES];
   [commentField selectText:self];
   [commentField setBordered:YES];
   [[self window] makeFirstResponder:commentField];
}

//***********************************
- (SSCatalystComment *)owner
{
   return owner;
}

- (void)setOwner:(SSCatalystComment *)own
{
   owner = own;
}

- (void)setTypeFromMenu:(NSMenuItem *)item
{
   [owner setType:[NSNumber numberWithInt:[item tag]]];
   [self setCommentImage];
}

- (void)setCommentImage
{
   [commentImage release];

   //get the correct image for our comment type
   switch([[owner type] intValue]) {
      case SSCommentQuestionType:commentImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"commentQuestion" ofType:@"tiff"]];
         break;
      case SSCommentNoteType:commentImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"commentNote" ofType:@"tiff"]];
         break;
      default:commentImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"commentAlert" ofType:@"tiff"]];
         break;
   }
   [commentImage setFlipped:YES];
   [self setNeedsDisplay:YES];
}

- (void)setPaths
{
   borderPath = [[NSBezierPath alloc] init];
   [borderPath setLineWidth:2];
   
   //create a border path with rounded edges
   [borderPath moveToPoint:NSMakePoint(0, 6)];
   [borderPath lineToPoint:NSMakePoint(0, (NSHeight([self frame]) - 6))];
   [borderPath curveToPoint:NSMakePoint(6, NSHeight([self frame]))
              controlPoint1:NSMakePoint(2, (NSHeight([self frame]) - 2))
              controlPoint2:NSMakePoint(4, (NSHeight([self frame]) - 4))];
   [borderPath lineToPoint:NSMakePoint((NSWidth([self frame]) - 6), NSHeight([self frame]))];
   [borderPath curveToPoint:NSMakePoint(NSWidth([self frame]), (NSHeight([self frame]) - 6))
              controlPoint1:NSMakePoint((NSWidth([self frame]) - 4), (NSHeight([self frame]) - 2))
              controlPoint2:NSMakePoint((NSWidth([self frame]) - 2), (NSHeight([self frame]) - 4))];
   [borderPath lineToPoint:NSMakePoint(NSWidth([self frame]), 6)];
   [borderPath curveToPoint:NSMakePoint((NSWidth([self frame]) - 6), 0)
              controlPoint1:NSMakePoint((NSWidth([self frame]) - 2), 4)
              controlPoint2:NSMakePoint((NSWidth([self frame]) - 4), 2)];
   [borderPath lineToPoint:NSMakePoint(6, 0)];
   [borderPath curveToPoint:NSMakePoint(0, 6)
              controlPoint1:NSMakePoint(4, 2)
              controlPoint2:NSMakePoint(2, 4)];
}

//***********************************
- (void)updateCommentString
{
   [commentField setStringValue:[owner commentString]];
   [self resizeSelfAndField];
}

//***********************************
- (void)resizeSelfAndField
{
   NSSize theSize = [[commentField cell] cellSizeForBounds:testCellBounds];
   NSRect oldFrame = [self frame];


   if(theSize.width < SSCommentFieldLength) {
      //there is no text or a very short string make the field the minimum width
      theSize.width = SSCommentFieldLength;
   }
   
   if(theSize.height < SSEventFieldHeight) {
      //they have removed all text so set the height to a single row
      theSize.height = SSEventFieldHeight;
   }
   
   [commentField setFrameSize:theSize];
   [self setFrameSize:NSMakeSize(NSWidth([self frame]), (NSHeight([commentField frame]) + 10))];

   if(NSHeight(oldFrame) > NSHeight([self frame])) {
      //the view has shrunk we need to get our superview to redraw the old frame to clean up
      [[self superview] setNeedsDisplayInRect:oldFrame];
   } else {
      [self setNeedsDisplay:YES];
   }
}

//***********************************
- (void)controlTextDidEndEditing:(NSNotification *)aNotification {
   if(![[commentField stringValue] isEqualToString:[owner commentString]]) {
      [self resizeSelfAndField];
      [owner setCommentString:[commentField stringValue]];
   }
}

- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView
doCommandBySelector:(SEL)commandSelector
{
   if(commandSelector == @selector(insertNewline:)) {
      //user pressed return end editing
      //deselect the field
      [commentField setSelectable:NO];
      [commentField setBordered:NO];
      [[self window] makeFirstResponder:[self window]];
      
      return YES;
   } else {
      return NO;
   }
}

//***********************************
- (void)resetCursorRects
{
   [self addCursorRect:[self visibleRect] cursor:[NSCursor arrowCursor]];
}

//***********************************

- (BOOL)isFlipped
{
   //changes the coordinate system so 0,0 is in the top left
   return YES;
}

//***********************************coding
- (void)encodeWithCoder:(NSCoder *)coder
{
   [super encodeWithCoder:coder];
   [coder encodeObject:owner forKey:@"owner"];
}

- (id)initWithCoder:(NSCoder *)coder
{
   if(self = [super initWithCoder:coder]) {
      [self setOwner:[coder decodeObjectForKey:@"owner"]];

      [self setPostsFrameChangedNotifications:YES]; //post a notification when our frame changes

      NSNotificationCenter *nc  = [NSNotificationCenter defaultCenter];
      [nc addObserver:self
             selector:@selector(setPaths)
                 name:@"NSViewFrameDidChangeNotification"
               object:self];
      
      [self setCommentImage];
      [self createMenu];
      [self setPaths];

      testCellBounds = NSMakeRect(0, 0, SSCommentFieldLength, 10000); //used to get a size for the text field

      imagePoint = NSMakePoint(2, 2);
      fromRect = NSMakeRect(0, 0, [commentImage size].width, [commentImage size].height);

      //setup the field
      NSEnumerator *enumerator = [[self subviews] objectEnumerator];
      id anObject;

      while (anObject = [enumerator nextObject]) {
         [anObject removeFromSuperview];
      }
      
      NSFont *font = [NSFont fontWithName:@"Helvetica" size:10];
      commentField = [[[NSTextField alloc]
          initWithFrame:NSMakeRect(([commentImage size].width + 3), 7, SSCommentFieldLength, SSEventFieldHeight)] autorelease];
      [commentField setStringValue:[owner commentString]];
      [[commentField cell] setBordered:NO];
      [[commentField cell] setFont:font];
      [commentField setDrawsBackground:NO];
      [commentField setDelegate:self];
      [commentField setSelectable:NO];
      [[commentField cell] setWraps:YES];
      [self addSubview:commentField];

      [self resizeSelfAndField]; //in case the string is too long to fit in a single field
      
   }

   return self;
}
//***********************************


- (void)dealloc
{
   [[NSNotificationCenter defaultCenter] removeObserver:self];
   
   [commentImage release];
   [commentMenu release];
   [super dealloc];
}

@end
